#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sqlite3.h>

#include "yonk.h"

#define BACKLOG 1024
#define PATH_INFO "./infomation.db"

int login(int consockfd, USER *user);
void quit();


void handler(int sig)
{
	while(0 < waitpid(-1, NULL, WNOHANG));
}

int main(int argc, char **argv)
{
	//socket;
	int sock_fd;
	if(0 > (sock_fd = socket(AF_INET, SOCK_STREAM, 0))){
		perror("sock_fd");
		return -1;
	}

	//bind;
	struct sockaddr_in serveraddr;
	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family 		= AF_INET;
	serveraddr.sin_port 		= atoi(argv[2]);		//	-> htons(8888);
	serveraddr.sin_addr.s_addr 	= inet_addr(argv[1]);	//	-> htons(INADDR_ANY);

	if(0 > bind(sock_fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))){
		perror("bind");	
		return -1;
	}

	//listen;
	if(0 > listen(sock_fd, BACKLOG)){
		perror("bind");
		return -1;
	}

	signal(SIGCHLD, handler);

	int consocket_fd;
	struct sockaddr_in clientaddr;
	bzero(&clientaddr, 0);
	socklen_t len = sizeof(clientaddr);
	
	while(1){
		consocket_fd = accept(sock_fd, (struct sockaddr *)&clientaddr, &len);
		if(0 > consocket_fd){
			perror("consocket_fd");
			return -1;
		}

		printf("ip:%s connecting ...\n",inet_ntoa(clientaddr.sin_addr));

		if(0 == fork()){
			close(sock_fd);			//close listen sockfd;
			int ret;
			USER user;
			while(1){
				bzero(&user, sizeof(user));
				ret = recv(consocket_fd, &user, sizeof(user), 0);
				if(0 > ret){
					fprintf(stderr, "recv false!\n");
					break;
				}
				printf("account:%s  password:%s\n",user.name,user.password);
			
				if(0 > login(consocket_fd, &user)){
					fprintf(stderr,"login error,try again please!\n");
					continue;
				}else
					break;
			}

			
			int option;
			while(1){
				puts("**********--->>>choice other opertions!<<<---**********");
				if(1 == user.type){
					if(0 > recv(consocket_fd, &option, sizeof(option), 0)){
						perror("recv");
						break;
					}

					switch(option){
						case 1:
							if(0 > append(consocket_fd)){
								fprintf(stderr, "append error,try and again Please!\n");
							}
							break;
							
						case 2:
							if(0 > delete(consocket_fd)){
								fprintf(stderr, "delete error,try and again Please!\n");
							}
							break;
							
						case 3:
							if(0 > modification(consocket_fd)){
								fprintf(stderr, "delete error,try and again Please!\n");
							}
							break;
							
						case 4:
							if(0 > acquire(consocket_fd)){
								fprintf(stderr, "delete error,try and again Please!\n");
							}
							break;
							
						case 5:
							quit();
							break;	
					}
					
				}else if(0 == user.type){
					if(0 > recv(consocket_fd, &option, sizeof(option), 0)){
						perror("recv");
						break;
					}

					switch(option){
						case 1:
							if(0 > acquire(consocket_fd)){
								fprintf(stderr, "append error,try and again Please!\n");
							}
							
							break;
							
						case 2:
							
							break;
							
						case 3:
							
							break;				
					}
				
				}


			}

			close(consocket_fd);
			exit(0);
		}
		
			
	}

	return 0;
}

int login(int consockfd, USER *user)
{
	sqlite3 *db;
	COMUNI comuni;
	bzero(&comuni, sizeof(comuni));
	if(SQLITE_OK != sqlite3_open(PATH_INFO, &db)){
		comuni.login_ack = 4;
		if(0 > send(consockfd, &comuni,sizeof(comuni), 0)){
			fprintf(stderr, "%d ->%s: send false!\n",__LINE__,__func__);
		}

		printf("error:%s\n", sqlite3_errmsg(db));
		exit(-1);
	}

	char **resultp = NULL;
	char *errmsg;
	int nrow, ncolumn;	
	if (0 != sqlite3_get_table(db, "select * from loginfo;", &resultp, &nrow, &ncolumn, &errmsg)) {		
		fprintf(stderr, "%d -> %s: sqlite3 get table: %s\n", __LINE__,__func__, errmsg);		
		exit(-1);	
	}	
	printf("sqlite3 get table success!\n");
	printf("ncolumn:%d nrow:%d\n",ncolumn, nrow);
	
	int count = 1 + ncolumn;	
	while(count < (nrow + 1) * ncolumn){
		if(!strcmp(user->name, resultp[count])){
			printf("I find this account!\n");
			if(*resultp[count + 2] == 1){
				printf("The account:%s has login yet!\n",user->name);
				comuni.login_ack = 3;		
				break;
			}

			if(!strcmp(user->password, resultp[count + 1])){
				char c = *resultp[count - 1];
				user->type = atoi(&c);
//questions!    *resultp[count + 2] = 1;
				comuni.login_ack = 0;
				printf("User account:%s login success!\n",user->name);
				break;
			}else{
				comuni.login_ack = 2;
				printf("User account:%s password error!\n",user->name);
				break;
			}
		}
		count += ncolumn;
	}
	if(count > ncolumn * ( nrow + 1)){
		comuni.login_ack = 1;
		printf("account:%s don't exists!\n",user->name);
	}

	if(0 > send(consockfd, &comuni, sizeof(comuni), 0)){
		fprintf(stderr,"%d -> %s send error!\n",__LINE__,__func__);
		return -1;
	}

	if(0 != sqlite3_close(db)){
			fprintf(stderr, "%d -> %s: %s\n", __LINE__,__func__,sqlite3_errmsg(db));
			return -1;
	}
	if(0 != comuni.login_ack){
		return -1;
	}

	if(0 > send(consockfd, &user->type, sizeof(user->type), 0)){
		fprintf(stderr,"%d -> %s send error!\n",__LINE__,__func__);
		return -1;
	}	
	
	return 0;
}

//	1:Admin;
int append(int consockfd)
{
	USER user;
	INFO info;
	sqlite3 *db;
	COMUNI comuni;
	bzero(&comuni, sizeof(comuni));
	bzero(&user,sizeof(user));
	bzero(&info,sizeof(info));

	if(0 > recv(consockfd, &info, sizeof(info), 0)){
		perror("recv");
		return -1;
	}

	char temp[50];
	bzero(temp,sizeof(temp));
	sprintf(temp, "%d",info.empnum);

	if(SQLITE_OK != sqlite3_open(PATH_INFO, &db)){
		if(0 > send(consockfd, &comuni,sizeof(comuni), 0)){
			fprintf(stderr, "%d ->%s: send false!\n",__LINE__,__func__);
		}

		printf("error:%s\n", sqlite3_errmsg(db));
		exit(-1);
	}

	char **resultp = NULL;
	char *errmsg;
	int nrow, ncolumn;	
	if (0 != sqlite3_get_table(db, "select * from employeeinfo;", &resultp, &nrow, &ncolumn, &errmsg)) {		
		fprintf(stderr, "%d -> %s: sqlite3 get table: %s\n", __LINE__,__func__, errmsg);		
		exit(-1);	
	}	
	printf("sqlite3 get table success!\n");
	printf("ncolumn:%d nrow:%d\n",ncolumn, nrow);

	int count = ncolumn;
	int flags = 0;
	while(count < (nrow + 1) * ncolumn){
		if(!strcmp(temp, resultp[count])){
			printf("I find this ID(employee number)!\n");
			flags = 1;
				break;
			}
		count += ncolumn;
	}

	if(1 == flags){
		comuni.choice = 12;			// 12 symbol employee number have exists!;
		if(0 > send(consockfd, &comuni, sizeof(comuni), 0)){
			perror("send");
			return -1;
		}
	}

	printf("Haven't record of employeenum:%d\n",info.empnum);
	
	char buf[300] = {0};
	sprintf(buf, "insert into employeeinfo values('%d','%s','%s','%s','%d','%lf','%d');",\
			info.empnum,info.name,info.phone,info.addr,info.age,info.salary,info.level);
	puts("----------------employee infomation--------------------");
	puts(buf);

	if(0 != sqlite3_exec(db, buf, NULL, NULL, &errmsg)){
		puts("********************--> error <--**********************");
		fprintf(stderr,"%d -> %s: sqlite3_exec: %s\n",__LINE__,__func__,errmsg);
		comuni.choice = 10;			// 10 symbol false!;
		if(0 > send(consockfd, &comuni, sizeof(comuni), 0)){
			perror("send");
			return -1;
		}
		return -1;
	}
	printf("*****--->>> append employee information success! <<<---*****\n");


	char loginbuf[100] = {0};
	sprintf(loginbuf, "insert into loginfo values('0','%d','0000','0');",info.empnum);
	puts("--------------------login infomation--------------------------");
	puts(loginbuf);
	
	if(0 != sqlite3_exec(db, loginbuf, NULL, NULL, &errmsg)){
		puts("********************--> error <--**********************");
		fprintf(stderr,"%d -> %s: sqlite3_exec: %s\n",__LINE__,__func__,errmsg);
		comuni.login_ack = 0;		// false!
	}
	else
		comuni.login_ack = 1;		//success!
	printf("*****--->>> append Login information success! <<<---*****\n");


	comuni.choice = 11;			// 11 symbol sucess!;
	if(0 > send(consockfd, &comuni, sizeof(comuni), 0)){
		perror("send");
		return -1;
	}

	if(0 != sqlite3_close(db)){
		fprintf(stderr, "%d -> %s: %s\n", __LINE__,__func__,sqlite3_errmsg(db));
		return -2;
	}	
	
	return 0;
}

//	2:Admin;
int delete(int consockfd)
{	
	USER user;
	sqlite3 *db;
	COMUNI comuni;
	bzero(&comuni, sizeof(comuni));
	bzero(&user,sizeof(user));

	if(0 > recv(consockfd, &user, sizeof(user), 0)){
		perror("recv");
		return -1;
	}
	
	if(SQLITE_OK != sqlite3_open(PATH_INFO, &db)){
		if(0 > send(consockfd, &comuni,sizeof(comuni), 0)){
			fprintf(stderr, "%d ->%s: send false!\n",__LINE__,__func__);
		}

		printf("error:%s\n", sqlite3_errmsg(db));
		exit(-1);
	}

	char **resultp = NULL;
	char *errmsg;
	int nrow, ncolumn;	
	if (0 != sqlite3_get_table(db, "select * from loginfo;", &resultp, &nrow, &ncolumn, &errmsg)) {		
		fprintf(stderr, "%d -> %s: sqlite3 get table: %s\n", __LINE__,__func__, errmsg);		
		exit(-1);	
	}	
	printf("sqlite3 get table success!\n");

	int count = ncolumn + 1;
	while(count < (nrow + 1) * ncolumn){
		if(!strcmp(user.name, resultp[count])){
			printf("I find this ID(employee number)!\n");

			char buf[300] = {0};
			sprintf(buf, "delete from loginfo where ID='%s';",user.name);
			printf("delete infomation:------------%s\n",buf);
			
			if(0 != sqlite3_exec(db, buf, NULL, NULL, &errmsg)){
				puts("********************--> error <--**********************");
				fprintf(stderr,"%d -> %s: sqlite3_exec(delete): %s\n",__LINE__,__func__,errmsg);
				break;
			}
			comuni.choice = 110;

			bzero(buf, sizeof(buf));
			sprintf(buf, "delete from employeeinfo where ID='%s';",user.name);
			if(0 != sqlite3_exec(db, buf, NULL, NULL, &errmsg)){
				puts("********************--> error <--**********************");
				fprintf(stderr,"%d -> %s: sqlite3_exec(delete): %s\n",__LINE__,__func__,errmsg);
				break;
			}
			comuni.choice = 111;
			break;
		}
		count += ncolumn;
	}

	if(count < (nrow + 1) * ncolumn){
		if(0 > send(consockfd, &comuni, sizeof(comuni), 0)){
			perror("send");
			return -1;
		}
	}else{
		fprintf(stderr,"%d -> %s >> account:%s doesn't exists!\n",__LINE__,__func__,user.name);
		comuni.choice = 100;
		if(0 > send(consockfd, &comuni, sizeof(comuni), 0)){
			perror("send");	
			return -1;
		}
		return -1;
	}

	puts("**************------>>>> delete success<<<------*************");
	return 0;
}

//	3:Admin(all) + User(part);
int modification(int sockfd)
{

	return 0;
}

//	4:Admin(all) + User(part);
int acquire(int sockfd)
{
	USER user;
	TRAN_INFO info;
	int count;
	sqlite3 *db;
	COMUNI comuni;
	bzero(&comuni, sizeof(comuni));
	bzero(&user, sizeof(user));
	
	if(0 > recv(sockfd, &user, sizeof(user), 0)){
		perror("recv");
		return -1;
	}
	
	if(SQLITE_OK != sqlite3_open(PATH_INFO, &db)){
		printf("error:%s\n", sqlite3_errmsg(db));
		exit(-1);
	}

	char **resultp = NULL;
	char *errmsg;
	int nrow, ncolumn;	
	if (0 != sqlite3_get_table(db, "select * from employeeinfo;", &resultp, &nrow, &ncolumn, &errmsg)) {		
		fprintf(stderr, "%d -> %s: sqlite3 get table: %s\n", __LINE__,__func__, errmsg);		
		exit(-1);	
	}	
	printf("%d -> %s:sqlite3 get table success!\n",__LINE__,__func__);	

	if(0 == user.type){
		bzero(&info, sizeof(info));
		count = ncolumn;
		while(count < (nrow + 1) * ncolumn){
			if(!strcmp(user.name, resultp[count])){
				printf("I find this ID(employee number)!\n");
					
				strcpy(info.empnum, resultp[count]);
				printf("empnum:%s\n",info.empnum);

				strcpy(info.addr, resultp[count + 3]);
				printf("addr:%s\n",info.addr);
				
				strcpy(info.age, resultp[count + 4]);
				printf("age:%s\n",info.age);

				strcpy(info.name, resultp[count + 1]);
				printf("name:%s\n",info.name);
				
				strcpy(info.level, resultp[count + 6]);
				printf("level:%s\n",info.level);
				
				strcpy(info.salary, resultp[count + 5]);
				printf("salary:%s\n",info.salary);

				strcpy(info.phone, resultp[count + 2]);
				printf("phone:%s\n",info.phone);
			
				if(0 > send(sockfd, &info, sizeof(info), 0)){
					perror("send");
					return -1;
				}
				break;
			}
			count += ncolumn;
		}
		
	}else if(1 == user.type){
		count = ncolumn;

		comuni.choice = nrow;
		if(0 > send(sockfd, &comuni, sizeof(comuni), 0)){
				perror("send");
				return -1;
		}
		
		while(count < (nrow + 1) * ncolumn){
			bzero(&info, sizeof(info));
			puts("----------------------------------------");
/*
			info.empnum 	= atoi(resultp[count]);
			printf("empnum:%d\n",info.empnum);
//			info.addr		= resultp[count + 3];
			strcpy(info.addr, resultp[count + 3]);
			printf("addr:%s\n",info.addr);
			info.age		= atoi(resultp[count + 4]);
			printf("age:%d\n",info.age);
//			info.name		= *resultp[count + 1];
			strcpy(info.name, resultp[count + 1]);
			printf("name:%s\n",info.name);
			info.level		= atoi(resultp[count + 6]);
			printf("level:%d\n",info.level);
			info.salary 	= strtod(resultp[count + 5], &p);
			printf("salary:%lf\n",info.salary);
//			info.phone		= *resultp[count + 2];
			strcpy(info.phone, resultp[count + 2]);
			printf("phone:%s\n",info.phone);
*/

			
			
			strcpy(info.empnum, resultp[count]);
			printf("empnum:%s\n",info.empnum);

			strcpy(info.addr, resultp[count + 3]);
			printf("addr:%s\n",info.addr);
			
			strcpy(info.age, resultp[count + 4]);
			printf("age:%s\n",info.age);

			strcpy(info.name, resultp[count + 1]);
			printf("name:%s\n",info.name);
			
			strcpy(info.level, resultp[count + 6]);
			printf("level:%s\n",info.level);
			
			strcpy(info.salary, resultp[count + 5]);
			printf("salary:%s\n",info.salary);

			strcpy(info.phone, resultp[count + 2]);
			printf("phone:%s\n",info.phone);

			
			


			if(sizeof(info) != send(sockfd, &info, sizeof(info), 0)){
				fprintf(stderr,"%d -> %s:send error!",__LINE__,__func__);
				continue;
			}

			count += ncolumn;
		}
	}

	return 0;
}

//	5:Admin + User;
void quit()
{

}
